package vlcjdemo;

import com.jtrustn.VideoClipser.MovDBhmi;
import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.swing.AbstractButton;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
/*
 * DelDub.java
 *
 * Created on 13. juni 2005, 22:42
 */

/**
 *
 * @author jtn2
 */
public class MovDB implements ImageList.RenderValues, MouseListener, ListSelectionListener, KeyListener {

    Map fileList;
    Map tagsList;
    String mapFileName = "MovDB.db";
    String tagsFileName = "MovDB.tags";
    String curDir = "." + File.separator;
    MovDBhmi movdbhmi;
    ScanMov aScanMov;
    ImageList aIconImageList;
    DateFormat formatter = new SimpleDateFormat("H:mm:ss.SSS");
    JFileChooser fc = new JFileChooser();
    final int tagsNbr = 2 * 30;
    JCheckBox[] tagsCheckBox = new JCheckBox[tagsNbr];
    boolean listChanged = false;
    long tagId = 0;
    Object[] tagsArr;

    /**
     * Creates a new instance of DelDub
     */
    public MovDB(MovDBhmi lmovdbhmi) {
        movdbhmi = lmovdbhmi;
        formatter.setTimeZone(java.util.TimeZone.getTimeZone("Zulu"));
        try {
            loadSettings(movdbhmi);
        } catch (Exception e) {
            e.printStackTrace();
        }

        openList();

        Object[] items = updateDBArr();

        aIconImageList = new ImageList((int) FFprobeParser.thumbNailWidth + 6, (int) 150 + 24, MovDB.this, items);
        JComponent aImageListView = aIconImageList.getView();
        aIconImageList.addMouseListener(this);
        aIconImageList.addKeyListener(this);
        aIconImageList.addListSelectionListener(this);
        movdbhmi.iconPanel.add(aImageListView, BorderLayout.CENTER);

        ActionListener actionListener = new ActionListener() {

            public void actionPerformed(ActionEvent actionEvent) {
                AbstractButton abstractButton = (AbstractButton) actionEvent.getSource();
                boolean selected = abstractButton.getModel().isSelected();
                insertTag(abstractButton.getText(), selected);
            }
        };

        for (int i = 0; i < tagsNbr; i++) {
            tagsCheckBox[i] = new JCheckBox();
            tagsCheckBox[i].addActionListener(actionListener);
            movdbhmi.tagsPanel.add(tagsCheckBox[i]);
        }
        updateTags();
    }

    public void renameRoot(String from, String to) {
        try {
            Set set2 = fileList.entrySet();
            Iterator itr2 = set2.iterator();
            while (itr2.hasNext()) {
                Map.Entry entry2 = (Map.Entry) itr2.next();
                Mov mov = (Mov) entry2.getValue();

                Set set = mov.info.entrySet();
                Iterator itr = set.iterator();
                while (itr.hasNext()) {
                    Map.Entry entry = (Map.Entry) itr.next();

                    if (entry.getValue() instanceof Set) {
                        Set filenames = (Set) entry.getValue();
                        Object[] arr = filenames.toArray();
                        for (Object object : arr) {
                            String filename = (String) object;
                            if (filename.startsWith(from)) {
                                String temp = filename.replace(from, to);
                                filenames.remove(filename);
                                filenames.add(temp);
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void openMovDB() {
        final File[] f = openFile(true);
        if (f != null && f.length > 0) {
            if (f[0].exists()) {
                saveList();
                curDir = f[0].getParent() + File.separator;
                openList();
                Object[] items = updateDBArr();
                aIconImageList.setItems(items);
                updateTags();
            }
        }

    }

    Object[] updateDBArr() {

        ArrayList items = new ArrayList();
        Iterator itr = fileList.values().iterator();
        while (itr.hasNext()) {
            Mov mov = (Mov) itr.next();
            Set filenames = (Set) mov.info.get("filename");
            if (filenames.size() > 0) {
                items.add(mov);
            }
        }

        return items.toArray();
    }

    void openList() {
        try {
            File filemap = new File(curDir + mapFileName);
            if (filemap.exists()) {
                ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(filemap)));
                fileList = (Map) in.readObject();
                in.close();
            } else {
                fileList = new HashMap();
            }
        } catch (Exception e) {
            System.out.println("Error: " + e);
        }
        try {
            File filemap = new File(curDir + tagsFileName);
            if (filemap.exists()) {
                ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(filemap)));
                tagId = in.readLong();
                tagsList = (Map) in.readObject();
                in.close();
            } else {
                tagId = 0;
                tagsList = new HashMap();
            }
        } catch (Exception e) {
            System.out.println("Error: " + e);
        }
        aScanMov = new ScanMov(fileList, this);
        File iconFileDir = new File(curDir + "img");
        if (!iconFileDir.exists()) {
            iconFileDir.mkdir();
        }
        listChanged = false;
    }

    public void saveSettings(JFrame frame) throws IOException {
        Properties settings = new Properties();
        try {
            settings.load(new FileInputStream("MovDB.props"));
        } catch (Exception e) {
            settings.clear();
            e.printStackTrace();
        }
        String name = frame.getName();

        settings.setProperty(name + ".x", "" + frame.getX());
        settings.setProperty(name + ".y", "" + frame.getY());
        settings.setProperty(name + ".w", "" + frame.getWidth());
        settings.setProperty(name + ".h", "" + frame.getHeight());
        String disp = frame.getGraphicsConfiguration().getDevice().getIDstring();
        settings.setProperty(name + ".d", disp);
        settings.setProperty("LastDB", curDir);
        settings.store(new FileOutputStream("MovDB.props"), null);
    }

    public void loadSettings(JFrame frame) throws IOException {
        Properties settings = new Properties();
        settings.load(new FileInputStream("MovDB.props"));
        String name = frame.getName();
        int x = getPropInt(settings, name + ".x", 100);
        int y = getPropInt(settings, name + ".y", 100);
        int w = getPropInt(settings, name + ".w", 500);
        int h = getPropInt(settings, name + ".h", 500);
        String disp = settings.getProperty(name + ".d");
        GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
        boolean found = false;
        for (GraphicsDevice graphicsDevice : devices) {
            if (disp.equals(graphicsDevice.getIDstring())) {
                found = true;
                break;
            }
        }

        if (found) {
            frame.setLocation(x, y);
            frame.setSize(new Dimension(w, h));
            frame.validate();
        }
        curDir = settings.getProperty("LastDB", "." + File.separator);
    }

    public static int getPropInt(Properties props, String name, int value) {
        String v = props.getProperty(name);
        if (v == null) {
            return value;
        }
        return Integer.parseInt(v);

    }

    public void insertTag(String tagStr, boolean selected) {
        Object[] sel = aIconImageList.getSelectedObjects();
        if (sel.length > 0) {
            try {
                Tag tag = (Tag) tagsList.get(tagStr);
                Mov mov = (Mov) sel[0];

                if (tag == null) {
                    tag = new Tag();
                    tag.id = tagId;
                    tagId++;
                    tag.count = 1;
                    tag.tag = tagStr;
                    tagsList.put(tagStr, tag);
                    mov.tags.add(tag.id);
                } else {
                    if (selected) {
                        tag.count++;
                        mov.tags.add(tag.id);
                    } else {
                        tag.count--;
                        mov.tags.remove(tag.id);
                    }
                }
                listChanged = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            updateTags();
        }
    }

    void updateTags() {
        tagsArr = tagsList.values().toArray();
        Arrays.sort(tagsArr);
        for (int i = 0; i < tagsCheckBox.length; i++) {
            if (i < tagsArr.length) {
                tagsCheckBox[i].setText(((Tag) tagsArr[i]).tag);
                tagsCheckBox[i].setSelected(false);
                tagsCheckBox[i].setEnabled(true);
            } else {
                tagsCheckBox[i].setText("");
                tagsCheckBox[i].setSelected(false);
                tagsCheckBox[i].setEnabled(false);
            }
        }
        Object[] sel = aIconImageList.getSelectedObjects();
        if (sel.length > 0) {
            try {
                Mov mov = (Mov) sel[0];
                for (int i = 0; i < tagsCheckBox.length; i++) {
                    if (i < tagsArr.length) {
                        if (mov.tags.contains(((Tag) tagsArr[i]).id)) {
                            tagsCheckBox[i].setSelected(true);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    File[] openFile(boolean multiFile) {
        File[] ret = null;
        fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        fc.setMultiSelectionEnabled(multiFile);
        fc.setDialogTitle("Open movie file .....");
        int result = fc.showOpenDialog(movdbhmi);

        // Determine which button was clicked to close the dialog
        switch (result) {
            case JFileChooser.APPROVE_OPTION:
                ret = fc.getSelectedFiles();
                break;
            case JFileChooser.CANCEL_OPTION:
                break;
            case JFileChooser.ERROR_OPTION:
                break;
        }
        return ret;
    }

    void deleteMovies(Object[] sel) {
        List deleteList = new ArrayList();
        try {
            Set set2 = fileList.entrySet();
            Iterator itr2 = set2.iterator();
            while (itr2.hasNext()) {
                Map.Entry entry2 = (Map.Entry) itr2.next();
                Mov mov = (Mov) entry2.getValue();

                for (Object object : sel) {
                    if (mov.equals(object)) {
                        deleteList.add(entry2);
                    }
                }
            }
            Object[] delArr = deleteList.toArray();
            for (Object object : delArr) {
                deleteMov((Map.Entry) object, true);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void deleteMovs() {
        final Object[] sel = aIconImageList.getSelectedObjects();


        int response = JOptionPane.showConfirmDialog(null, "Do you want to delete " + sel.length + " files?", "Confirm",
                JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
        if (response == JOptionPane.NO_OPTION) {
        } else if (response == JOptionPane.YES_OPTION) {
            movdbhmi.statusLabel.setText("Deleting...");
            Thread aThread = new Thread() {

                public void run() {
                    deleteMovies(sel);
                    listChanged = true;
                    saveList();
                    SwingUtilities.invokeLater(new Runnable() {

                        public void run() {
                            Object[] items = updateDBArr();
                            aIconImageList.setItems(items);
                            movdbhmi.statusLabel.setText("");
                        }
                    });
                }
            };
            aThread.start();
        } else if (response == JOptionPane.CLOSED_OPTION) {
        }
    }

    void cleanDir(File[] farr) {
        List deleteList = new ArrayList();
        for (File file : farr) {
            if (file.isDirectory()) {
                try {
                    String str = file.getCanonicalPath();
                    Set set2 = fileList.entrySet();
                    Iterator itr2 = set2.iterator();
                    while (itr2.hasNext()) {
                        Map.Entry entry2 = (Map.Entry) itr2.next();
                        Mov mov = (Mov) entry2.getValue();

                        Set set = mov.info.entrySet();
                        Iterator itr = set.iterator();
                        while (itr.hasNext()) {
                            Map.Entry entry = (Map.Entry) itr.next();

                            if (entry.getValue() instanceof Set) {
                                Set filenames = (Set) entry.getValue();
                                Object[] arr = filenames.toArray();
                                for (Object object : arr) {
                                    String filename = (String) object;
                                    if (filename.startsWith(str)) {
                                        File aFile = new File(filename);
                                        if (!aFile.exists()) {
                                            filenames.remove(object);
                                            if (filenames.isEmpty()) {
                                                deleteList.add(entry2);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }

        Object[] delArr = deleteList.toArray();
        for (Object object : delArr) {
            deleteMov((Map.Entry) object, false);
        }
    }

    void deleteMov(Map.Entry entry, boolean deleteMovie) {
        Mov mov = (Mov) entry.getValue();
        try {
//            for (int i = 0; i < tagsArr.length; i++) {
//                if (mov.tags.contains(((Tag) tagsArr[i]).id)) {
//                    ((Tag) tagsArr[i]).count--;
//                }
//            }
//            fileList.remove(entry.getKey());
            String theUrl = curDir + "img" + File.separator + "MovDB_" + (Long) mov.info.get("Checksum") + ".jpg";
            File imgFile = new File(theUrl);
            imgFile.delete();
            Set set = mov.info.entrySet();
            Iterator itr = set.iterator();
            while (itr.hasNext()) {
                Map.Entry entry2 = (Map.Entry) itr.next();
                if (entry2.getValue() instanceof Set) {
                    Set filenames = (Set) entry2.getValue();
                    if (deleteMovie) {
                        Object[] arr = filenames.toArray();
                        for (Object object : arr) {
                            try {
                                String filename = (String) object;
                                File movieFile = new File(filename);
                                movieFile.delete();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    filenames.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void cleanUp() {
        final File[] f = openFile(true);
        if (f != null) {
            movdbhmi.statusLabel.setText("Cleaning...");
            Thread aThread = new Thread() {

                public void run() {
                    cleanDir(f);
                    listChanged = true;
                    saveList();
                    SwingUtilities.invokeLater(new Runnable() {

                        public void run() {
                            Object[] items = updateDBArr();
                            aIconImageList.setItems(items);
                            movdbhmi.statusLabel.setText("");
                        }
                    });
                }
            };
            aThread.start();
        }
    }

    public void importMov() {
        final File[] f = openFile(true);
        if (f != null) {
            movdbhmi.statusLabel.setText("Importing...");
            Thread aThread = new Thread() {

                public void run() {
                    aScanMov.scan(f);
                    listChanged = true;
                    saveList();
                    SwingUtilities.invokeLater(new Runnable() {

                        public void run() {
                            Object[] items = updateDBArr();
                            aIconImageList.setItems(items);
                            movdbhmi.statusLabel.setText("");
                        }
                    });
                }
            };
            aThread.start();
        }
    }

    public void play() {
        Object[] sel = aIconImageList.getSelectedObjects();
        if (sel.length > 0) {
            try {
                Mov mov = (Mov) sel[0];
                Set filenames = (Set) mov.info.get("filename");
                Object[] arr = filenames.toArray();
                String document = (String) arr[0];
                Desktop dt = Desktop.getDesktop();
                dt.open(new File(document));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    public String getSelectedMov() {
        String ret = null;
        Object[] sel = aIconImageList.getSelectedObjects();
        if (sel.length > 0) {
            try {
                Mov mov = (Mov) sel[0];
                Set filenames = (Set) mov.info.get("filename");
                Object[] arr = filenames.toArray();
                ret = (String) arr[0];
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    void searchMov(String tag, List foundtags, Map input, Map movs) {
        Set set2 = input.entrySet();
        Iterator itr2 = set2.iterator();
        while (itr2.hasNext()) {
            boolean found = false;
            Map.Entry entry2 = (Map.Entry) itr2.next();
            Mov mov = (Mov) entry2.getValue();

            Set set = mov.info.entrySet();
            Iterator itr = set.iterator();
            while (itr.hasNext()) {
                Map.Entry entry = (Map.Entry) itr.next();

                if (entry.getValue() instanceof Set) {
                    Set filenames = (Set) entry.getValue();
                    Object[] arr = filenames.toArray();
                    for (Object object : arr) {
                        if (((String) object).toLowerCase().contains(tag)) {
                            found = true;
                        }
                    }
                } else if (entry.getValue() instanceof Date) {
                } else if (entry.getValue() instanceof Long) {
                } else {
                    if (((String) entry.getValue()).toLowerCase().contains(tag)) {
                        found = true;
                    }
                }
            }

            if (!found) {
                Iterator itr3 = foundtags.iterator();
                while (itr3.hasNext()) {
                    Tag ftag = (Tag) itr3.next();
                    if (mov.tags.contains(ftag.id)) {
                        found = true;
                        break;
                    }
                }
            }

            if (found) {
                movs.put(entry2.getKey(), entry2.getValue());
            }
        }
    }

    public void search() {
        Map movs = new HashMap();
        String[] sarr = movdbhmi.searchTextField.getText().toLowerCase().split(" ");
        Map inputList = fileList;
        List foundtags = new ArrayList();
        for (String string : sarr) {
            foundtags.clear();
            for (Object obj : tagsArr) {
                Tag tag = (Tag) obj;
                if (tag.tag.toLowerCase().contains(string)) {
                    foundtags.add(tag);
                }
            }
            searchMov(string, foundtags, inputList, movs);
            if (!movdbhmi.andorToggleButton.isSelected()) {
                inputList = movs;
                movs = new HashMap();
            }
        }
        Object[] items = null;
        if (!movdbhmi.andorToggleButton.isSelected()) {
            items = inputList.values().toArray();
        } else {
            items = movs.values().toArray();
        }
        aIconImageList.setItems(items);
    }

    public void reset() {
        Object[] items = updateDBArr();
        aIconImageList.setItems(items);
    }

    public void saveList() {
        if (listChanged) {
            try {
                ObjectOutput out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(curDir + mapFileName)));
                out.writeObject(fileList);
                out.close();
            } catch (Exception e) {
                System.out.println("Error: " + e);
            }
            listChanged = false;
            try {
                ObjectOutput out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(curDir + tagsFileName)));
                out.writeLong(tagId);
                out.writeObject(tagsList);
                out.close();
            } catch (Exception e) {
                System.out.println("Error: " + e);
            }
        }
        try {
            saveSettings(movdbhmi);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void requestCellImage(ImageList list, Object obj, int imageWidth, int imageHeight) {
        Mov mov = (Mov) obj;

        Set filenames = (Set) mov.info.get("filename");
        if (filenames.size() > 0) {
            String theUrl = curDir + "img" + File.separator + "MovDB_" + (Long) mov.info.get("Checksum") + ".jpg";
            ImageIcon anotherIcon = new ImageIcon(theUrl);

            try {
                int type = BufferedImage.TYPE_INT_RGB;
                BufferedImage bimage = new BufferedImage(imageWidth, imageHeight, type);
                Graphics g = bimage.createGraphics();
                Image aImage = anotherIcon.getImage();
                g.drawImage(aImage, 0, 0, null);
                g.dispose();

                list.putImage(obj, bimage);
                aImage.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("Empty filenames: " + mov.info.get("Checksum"));
            list.putImage(obj, null);
        }
    }

    @Override
    public String getCellText(ImageList list, Object obj) {
        Mov mov = (Mov) obj;
        Set filenames = (Set) mov.info.get("filename");
        Object[] arr = filenames.toArray();
        if (arr.length > 0) {
            File f = new File((String) arr[0]);
            return f.getName();
        } else {
            return "";
        }
    }

    @Override
    public String getTooltipText(ImageList list, FontMetrics tooltipMetrics, Object obj) {
//        Mov mov = (Mov) obj;
//        Date date = (Date) mov.info.get("duration");
//        String timeStr = formatter.format(date);
//        return "Duration: " + timeStr;
        Mov mov = (Mov) obj;
        Set filenames = (Set) mov.info.get("filename");
        Object[] arr = filenames.toArray();
        if (arr.length > 0) {
            File f = new File((String) arr[0]);
            return f.getPath();
        } else {
            return "";
        }
    }

    void showDetails() {
        Object[] sel = aIconImageList.getSelectedObjects();
        if (sel.length > 0) {
            movdbhmi.detailsTextArea.setText("");
            Mov mov = (Mov) sel[0];
            Set set = mov.info.entrySet();
            Iterator itr = set.iterator();
            while (itr.hasNext()) {
                Map.Entry entry = (Map.Entry) itr.next();
                if (entry.getValue() instanceof Set) {
                    Set filenames = (Set) entry.getValue();
                    Object[] arr = filenames.toArray();
                    for (Object object : arr) {
                        movdbhmi.detailsTextArea.append(entry.getKey() + " : " + object + "\n");
                    }
                } else if (entry.getValue() instanceof Date) {
                    Date date = (Date) entry.getValue();
                    String timeStr = formatter.format(date);
                    movdbhmi.detailsTextArea.append(entry.getKey() + " : " + timeStr + "\n");
                } else {
                    movdbhmi.detailsTextArea.append(entry.getKey() + " : " + entry.getValue() + "\n");
                }
            }
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getSource() == aIconImageList.list) {
            showDetails();
            updateTags();
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void valueChanged(ListSelectionEvent e) {
        if (!e.getValueIsAdjusting()) {
            showDetails();
            updateTags();
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            play();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
}
